//-----------------------------------------------------------------------------
// Filename: SecureMessageBoardController.cs
//
// Description: A controller class that implements message board functionality.
//
// History:
// 02 Mar 2004	Aaron Clauson	Created.
// 09 Sep 2004	Aaron Clauson	Combined MessageBoard and SecureMessageBoard
//								controllers.
//
// License: 
// Public Domain.
//-----------------------------------------------------------------------------

using System;
using System.Collections;
using System.Text.RegularExpressions;
using System.Xml;
using MaverickLite.Aza.Model;
using MaverickLite.Config;
using MaverickLite.Controller;
using MaverickLite.Security;
using log4net;

namespace MaverickLite.Aza.Controller
{
	/// <summary>
	/// Controller that implements message board functionality.
	/// </summary>
	public class SecureMessageBoardController : SecureXmlController
	{
		private const string EDITABLE_PATH_KEY = "editablePath";
		private const string SELFEDITOR_ACTION_KEY = "editaction";			// The name of the field used in HTTP requests to request a page action.
		private const string ANONYMOUS_AUTHOR_NAME = "anonymous";
		
		private const string ADD_ACTION_KEY = "add";
		private const string UPDATE_ACTION_KEY = "update";
		
		private const string ROOT_NODE_NAME = "page";
		private const string CONTENT_NODE_NAME = "contents";
		private const string MESSAGE_NODE_NAME = "message";
		private const string AUTHOR_ELEMENT_NAME = "author";
		private const string CONTENT_ELEMENT_NAME = "content";
		private const string CREATIONTIME_ELEMENT_NAME = "creationTime";
		private const string IPADDRESS_ELEMENT_NAME = "ipaddress";
		private const string ID_ATTRIBUTE_NAME = "id";

		protected string m_editAction;
		protected string m_editMetadataPath;
		protected SelfEditingModel m_editModel;
		protected bool m_editError = false;

		public SecureMessageBoardController(XmlElement initParams) : base(initParams)
		{
			// Load the self editing model.
			m_editMetadataPath = MavAppState.GetPath((string)SimpleParameters[EDITABLE_PATH_KEY]);
			logger.Debug("MessageBoardController created with metadata path of, " + m_editMetadataPath + ".");
		}

		public override string Perform()
		{
			try
			{
				m_editError = false;
				m_editAction = MavRequestState.GetRequestValue(SELFEDITOR_ACTION_KEY);
				m_editModel = new SelfEditingModel(m_editMetadataPath, null);

				// Depending on the action selected and the request parameters perform the appropriate
				// actions on the model.
				if(m_editModel != null && m_editAction != null && Regex.Match(m_editAction, ADD_ACTION_KEY, RegexOptions.IgnoreCase).Success)
				{
					if(!m_authenticated && m_authenticationAction != null && Regex.Match(m_authenticationAction, "true", RegexOptions.IgnoreCase).Success)
					{
						logger.Error("This message board requires you to be authenticated in order to add a message.");
						AddErrorMessage("This message board requires you to be authenticated in order to add a message.");
						return null;
					}
					
					Hashtable requestData = MavRequestState.GetRequestData();

					// No new messages to add.
					if(requestData == null)
					{
						return null;
					}

					string author = null;

					if(m_authenticatedCredentials != null)
					{
						author = m_authenticatedCredentials.Username;
					}
					else
					{
						author = (string)requestData["author"];
					}

					if(author == null || author.Trim() == String.Empty)
					{
						author = ANONYMOUS_AUTHOR_NAME;
					}

					string contents = (string)requestData["contents"];

					if(contents == null || contents.Trim() == String.Empty)
					{
						logger.Warn("There were no message contents to add.");
						AddErrorMessage("There were no message contents to add.");
						return null;
					}

					//DateTime gmtTime = DateTime.Now.ToUniversalTime();
					DateTime gmtTime = DateTime.Now;

					string messageItemName = "message";
					string messageItemContents = 
						"<" + AUTHOR_ELEMENT_NAME + ">" + author + "</" + AUTHOR_ELEMENT_NAME + ">" +
						"<" + CONTENT_ELEMENT_NAME + ">" + contents + "</" + CONTENT_ELEMENT_NAME + ">" + 
						"<" + CREATIONTIME_ELEMENT_NAME + ">" + gmtTime.ToString("ddd dd MMM yyyy hh:mm:ss") + "</" + CREATIONTIME_ELEMENT_NAME + ">" +
						"<" + IPADDRESS_ELEMENT_NAME + ">" + MavRequestState.RequestIPAddress + "</" + IPADDRESS_ELEMENT_NAME + ">";

					// Pass the data and request credentials in order to add a new node to the model.
					m_editModel.Add(messageItemName, messageItemContents, null);
				}

				return null;
			}
			catch(Exception editModelExcp)
			{
				m_editError = true;

				// Add all the request data to the page model so that it can be used by the error page if required.
				// For instance if someone has just submitted a big form of data rather then just giving an error message
				// you also want to give back the data to save them typing it again!
				try
				{
					string requestData = "<page><requestData>";
					
					foreach(string key in MavRequestState.GetRequestData().Keys)
					{
						requestData += "<incoming id='" + key + "'><![CDATA[" + MavRequestState.GetRequestValue(key) + "]]></incoming>";
					}

					requestData += "</requestData></page>";

					m_pageModel.AddToModel(requestData, true);
				}
				catch(Exception excp)
				{
					logger.Error("Exception attempting to add the request data to the page model. " + excp.Message);
				}
				
				logger.Error("Exception MessageBoardController: " + editModelExcp.Message);
				AddErrorMessage("The message board controller threw an exception, the model path was, " + m_editMetadataPath + ". " + editModelExcp.Message);
				return null;
			}
		}

		public override void BuildPageModel()
		{
			// Add the editing model to the model for the page.
			if(m_editModel != null)
			{
				XmlDocument messageBoardModel = m_editModel.GetModel();

				// Order the model to place the most recent messages first.
				XmlDocument orderedModel = new XmlDocument();
				orderedModel.LoadXml("<" + ROOT_NODE_NAME + "><" + CONTENT_NODE_NAME + "/></" + ROOT_NODE_NAME + ">");
				XmlNode contentNode = orderedModel.DocumentElement.SelectSingleNode(CONTENT_NODE_NAME);

				logger.Debug("Ordering the message board model messages.");

				// New messages are appended to the end of the file so to order them just reverse.
				XmlNode boardContents = messageBoardModel.DocumentElement.SelectSingleNode(CONTENT_NODE_NAME);
				int numberMessages = boardContents.ChildNodes.Count;

				for(int index=numberMessages-1; index>=0; index--)
				{
					XmlElement messageElement = orderedModel.CreateElement(MESSAGE_NODE_NAME);
					messageElement.InnerXml = boardContents.ChildNodes[index].InnerXml;
					contentNode.AppendChild(messageElement);
				}

				m_pageModel.AddToModel(orderedModel.DocumentElement, false);
			}
		}

		public override string GetView()
		{
			 if(m_editError || m_editAction == "edit")
			{	
				if(!m_authenticated && m_authenticationAction != null && Regex.Match(m_authenticationAction, "true", RegexOptions.IgnoreCase).Success)
				{
					AddAuthenticationRequest();
				}
								
				return "edit";
			}
			else
			{
				return "success";
			}
		}
	}
}
